home *** CD-ROM | disk | FTP | other *** search
- /*
-
- QLTOOLS
-
- Read a QL floppy disk
-
- (c)1992 by Giuseppe Zanetti
-
- Giuseppe Zanetti
- via Vergani, 11 - 35031 Abano Terme (Pdaova) ITALY
- e-mail: beppe@sabrina.dei.unipd.it
-
- Think C adaption Roberto Avanzi
- via Luigi Balzan 12 - 45100 Rovigo ITALY
- e-mail: gandalf@sabrina.dei.unipd.it
-
- */
-
- #define VERSION 1.0 Sep 24 1992
-
- #include <stdio.h>
- #ifdef THINK_C
- #include "console.h"
- #include <string.h>
- #else
- #include <strings.h>
- #endif
-
- /* this line is neccessary since stdio.h in SUN 4.0 do not define it */
-
- #ifndef SEEK_SET
- #define SEEK_SET 0
- #endif
-
- FILE *f;
- static unsigned char b[512*3];
- static unsigned char b0[512*3];
- static unsigned char ltp[18];
- static unsigned char ptl[18];
- static unsigned long int bleod;
- static unsigned char byeod;
- static unsigned char *pdir;
-
- static unsigned int convtable[1440];
-
- static int gsides,gtracks,gsectors,goffset;
-
- long int lwrd(p)
- unsigned char *p;
- {
- return ( (long int) ( *(p+3) + *(p+2)*0x100 + *(p+1)*0x10000 + *(p)*0x1000000 ) );
- }
-
- void cat_file(fnum)
- long int fnum;
- {
- long int flen,file,blk;
- int i,s,c,start,end;
- char buffer[512*3];
- unsigned char *base;
-
- flen=lwrd(pdir+fnum*64); /* with the header */
-
- /* printf("cat file #%i len=%ld blocks=%ld + %d\n\n",fnum,flen,flen/(512*3),flen % (512*3)); */
-
- for (s=0;s<=flen/(512*3);s++)
- {
- for (i=0;i<(wrd(b0+28)*wrd(b0+30))/wrd(b0+32);i++)
- {
- base=b0+0x4C+20+i*3;
- file=(int) (*(base) * 0x10) + (int) ((*(base+1) >> 4) & 0x0F) ;
- blk= (*(base+1) & 0x0F)*0x100 + *(base+2);
-
- /* printf("%ld/%ld\n",file,blk); */
-
- if (file == fnum)
- {
- if (blk == s)
- {
- read_block(buffer,i);
-
- start=0; if (s==0) start=64;
- end=512*3; if (s==(flen/(512*3))) end=flen % (512*3);
-
- for(c=start;c<end;c++) printf("%c",*(buffer+c));
- }
- }
- }
- }
- }
-
- void usage(error)
- char *error;
- {
- fprintf(stderr,"error %s\n\n",error);
- fprintf(stderr,"Usage: qltools diskimage -[options] [filename]\n\n");
- fprintf(stderr,"options:\n\n");
- fprintf(stderr,"-d list directory\n");
- fprintf(stderr,"-i list info\n");
- fprintf(stderr,"-m list disk map\n");
- fprintf(stderr,"-c list conversion table of sectors\n");
- fprintf(stderr,"-nFN output file number NF in the directory listing\n\n");
- fprintf(stderr,"diskimage is either a file with the image of a QL format disk\n");
- fprintf(stderr,"or a unix device with a ql disk inserted in it (/dev/fd...)\n\n");
-
- fprintf(stderr,"Giuseppe Zanetti\n");
- fprintf(stderr,"via Vergani, 11 - 35031 Abano Terme (Pdaova) ITALY\n");
- fprintf(stderr,"e-mail: beppe@sabrina.dei.unipd.it\n");
- exit(1);
- }
-
-
- void print_info()
- {
- int i;
-
- printf("Disk Id : ");
-
- for (i=0;i<4;i++)
- {
- printf("%c",b0[i]);
- }
- printf("\n");
-
- printf("Disk Label : ");
-
- for (i=0;i<10;i++)
- {
- printf("%c",b0[4+i]);
- }
- printf("\n");
-
- printf("Sectors per track: %i\n",gsectors);
- printf("sectors per cyl. : %i\n",wrd(b0+28));
- printf("number of cylind.: %i\n",gtracks);
- printf("allocation block : %i\n",wrd(b0+32));
- printf("sector offset/cyl: %i\n",goffset);
-
- printf("free sectors : %i\n",wrd(b0+20));
- printf("good sectors : %i\n",wrd(b0+22));
- printf("total sectors : %i\n",wrd(b0+24));
-
- printf("directory is : %i sectors and %u bytes\n",bleod,byeod);
-
- printf("\nlogical-to-physical sector mapping table:\n\n");
- for (i=0;i<18;i++) printf("%u ",ltp[i]);
- printf("\n");
-
- printf("\nphysical-to-logical sector mapping table:\n\n");
- for (i=0;i<18;i++) printf("%u ",ptl[i]);
- printf("\n");
- }
-
- void print_dir()
- {
- int d,i;
- char c;
-
- for (i=0;i<10;i++)
- {
- printf("%c",b0[4+i]);
- }
- printf("\n");
-
- printf("%i/%i sectors.\n\n",wrd(b0+20),wrd(b0+22));
-
- for (d=64;d <512*bleod+byeod;d+=64)
- {
- printf("%3i : ",d/64);
-
- for (i=0;i<wrd(pdir+d+14);i++)
- {
- c=*(pdir+d+16+i);
-
- printf("%c",c);
- }
-
- for(i=0;i<38-wrd(pdir+d+14);i++) printf(" ");
-
- switch(*(pdir+d+5))
- {
- case 0: printf(" "); break;
- case 1: printf("executable"); break;
- case 2: printf("relocable "); break;
- default:printf("bad type "); break;
- }
-
- printf(" %ld\n",lwrd(pdir+d) - 64);
-
- }
- }
-
- void make_convtable(verbose)
- int verbose;
- {
- int i,si,tr,se,ls,ps,uxs;
-
- if (verbose)
- {
- printf("\nCONVERSION TABLE\n\n");
- printf("logic\ttrack\tside\tsector\tunix_dev\n\n");
- }
-
- for(i=0;i<gtracks*gsectors*gsides;i++)
- {
- tr=i / (gsectors*gsides);
- ls=i % (gsectors*gsides);
-
- ps = ltp[ls];
-
- si=(ps & 0x80) != 0;
-
- ps &= 0x7F;
-
- ps += goffset*tr;
- se = ps % gsectors;
-
- uxs = tr*gsectors*gsides+gsectors*si+se;
-
- convtable[i] = uxs;
-
- if (verbose)
- {
- printf("%i\t%i\t%i\t%i\t%i\n",i,tr,si,se,uxs);
- }
- }
- }
-
- int wrd(wp)
- char *wp;
- {
- int r;
-
- r=*(wp)*256 + *(wp+1);
-
- return r;
- }
-
-
- int read_block0()
- {
- int i;
-
- fseek(f,0,SEEK_SET);
- fread(b0,512,1,f);
-
- fseek(f,512*3,SEEK_SET);
- fread(b0+512,512,1,f);
-
- fseek(f,512*6,SEEK_SET);
- fread(b0+1024,512,1,f);
-
- /* read ptl and ptl tables */
-
- for (i=0;i<18;i++)
- {
- ltp[i] = *(b0+40+i);
- ptl[i] = *(b0+58+i);
- }
-
- return(0);
- }
-
- int read_block(p,num)
- char *p;
- int num;
- {
- int i;
- int r=0;
-
- for(i=0;i<3;i++)
- {
- fseek(f,(512*convtable[num*3+i]),SEEK_SET);
- r += fread(p+512*i,512,1,f);
- }
-
- return(r);
- }
-
-
- long int match_file(fname)
- char *fname;
- {
- int d,i,match,len;
- long int r=0L;
- char c;
-
- len=strlen(fname);
-
- for (d=64;d <512*bleod+byeod;d+=64)
- {
- match=1;
-
- if (wrd(pdir+d+14) == len)
- {
- for (i=0;i<len;i++)
- {
- c=*(pdir+d+16+i);
-
- if (c != fname[i]) match=0;
- }
-
- if (match)
- {
- r=d/64;
- break;
- }
- }
- }
-
- return(r);
- }
-
- main(argc,argv)
- int argc;
- char * argv[];
- {
- int i;
- unsigned long int finfofile, finfoblk;
- unsigned char *base;
-
- int argdir,arginfo,argfnum,argmap,argconv;
- char argfname[255];
-
- #ifdef THINK_C
- argc=ccommand(&argv);
- #endif
-
- argdir=arginfo=argfnum=argmap=argconv=0;
- strcpy(argfname,"");
-
- if (argc < 2)
- {
- usage("too few parameters");
- }
-
- for(i=2;i<argc;i++)
- {
- if (argv[i][0] == '-')
- {
- switch(argv[i][1])
- {
- case 'd': argdir=1; break;
- case 'i': arginfo=1; break;
- case 'm': argmap=1; break;
- case 'c': argconv=1; break;
- case 'n': argfnum=atol(argv[i]+2); break;
- default: usage("bad option"); break;
- }
- }
- else
- {
- strcpy(argfname,argv[i]);
- }
- }
-
- f=fopen(argv[1],"rb");
-
- if (f==NULL)
- {
- usage("bad image file or device");
- }
-
- read_block0();
-
- gsides=2;
- gtracks=wrd(b0+30);
- gsectors=wrd(b0+26);
- goffset=wrd(b0+38);
- bleod=wrd(b0+34);
- byeod=wrd(b0+36);
- pdir=(unsigned char *) malloc(512*(bleod+1));
-
- make_convtable(argconv);
-
-
- /* read the directory map */
-
- if (argmap)
- {
- printf("\nblock\tfile\tpos\n\n");
- }
-
- for (i=0;i<(wrd(b0+28)*wrd(b0+30))/wrd(b0+32);i++)
- {
- base=b0+0x4C+20+i*3;
-
- finfofile= (unsigned long int) (*(base) * 0x10) + (unsigned long int) ((*(base+1) >> 4) & 0x0F) ;
- finfoblk= (*(base+1) & 0x0F)*0x100 + *(base+2);
-
-
- if (finfofile == 0x00)
- {
- read_block(pdir+512*3*finfoblk,i);
- }
-
- if (argmap)
- {
- printf("%d\t%ld\t%ld\t",i,finfofile,finfoblk);
-
- switch(finfofile)
- {
- case 0x000: printf("directory %i\n",finfoblk); break;
- case 0xF80: printf("map\n"); break;
- case 0xFDF: printf("unused\n"); break;
- case 0xFEF: printf("bad\n"); break;
- case 0xFFF: printf("not existent\n"); break;
- default: printf("\n"); break;
- }
- }
- }
-
- if (arginfo) print_info();
- if (argdir) print_dir();
- if (argfnum != 0) cat_file(argfnum);
- if (strcmp(argfname,"") != 0)
- {
- argfnum=match_file(argfname);
-
- if (argfnum == 0)
- {
- fprintf(stderr,"file not found\n");
- exit(2);
- }
-
- cat_file(argfnum);
- }
-
- fclose(f);
- return (0);
- }
-
- /*
-
-
- What exactly do you want to know? I don't know about the
- 3.2MB format, but I can tell you about 720k. Allocation blocks are 3
- sectors long (normally. This can be changed) and the block 0
- (consisting of sectors 0, 3 and 6 of side 0 on cylinder 0) contains
- the mapping info. The first 96 bytes are used as follows:
- OFFSET SIZE VALUE
- $00 .L $514C3541
- $04 10 bytes disk label
- $0E .W random number (created by FORMAT)
- $10 .L #writes to this disk
- $14 .W #free sectors
- $16 .W #good sectors
- $18 .W total sectors
- $1A .W #sectors per track (9)
- $1C .W #sectors per cylinder (18 for DS)
- $1E .W number of cylinders (80)
- $20 .W size of allocation block (3)
- $22 .W block number for end-of-directory
- $24 .W byte number of end-of-directory
- $26 .W sector offset/cylinder
- $28 18 bytes logical-to-physical sector mapping table
- $3A 18 bytes physical-to-logical sector mapping table
- $4C 20 bytes unused
-
- The rest of the block consists of pairs of 12-bit values (24 bits for
- each block on a fully formatted, 80 track, double sided disk) the
- first of which contains the file number which that block belongs to,
- the seconds holds the position of this block within that file. Some
- special file numbers are used for the mapping block itself ($F80),
- unused blocks ($FDF), bad blocks ($FEF) and non-existant blocks ($FFF)
- and the block-number of unused, bad and non-existant blocks is always
- $FFF (but when a file is deleted, only the top byte is set to $FD)
- the map is $F80 000 - it consists of one block! The directory
- is file number $000, and all other files have numbers corresponding to
- their positions in the directory (file $001 is the first, $002 is the
- second, etc.)
- The "logical-to-physical sector mapping table" contains a byte
- for each sector on a cylinder (18) corresponding to the physical
- sector number (0 to 8, with the MSB set for sectors on side 1) for
- each logical file sector. This table is always "0 3 6 128 131 134 1 4
- 7 129 132 135 2 5 8 130 133 136" (unless someone has changed it)
- meaning sectors 0, 3, 6 of side 0 are used first, then sectors 0, 3, 6
- of side 1, then sectors 1, 4, 7 of side 0, etc. _BUT_ the sector
- number is offset by an amount depending on the cylinder number (the
- numbers above are correct for cylinder 0, but the "sector
- offset/track" value is added (mod 9) for each cylinder. This value is
- usually 5, so the table values are correct again at cylinder 9)
- The "physical-to-logical sector mapping table" contains 9
- entries for each side of the disk, containing the logical sector
- numbers of the physical sectors on the disk. It is "0 6 12 1 7 13 2 8
- 14" for side 0 and "3 9 15 4 1 16 5 11 17" for side 1 (that is, for
- side 0, phys. sector 0 contains log. sector 0, phys. sector 1 contains
- log. sector 6, ...) again, this is affected by the "sector
- offset/track".
-
- The directory consists of 64 '0's ($30 bytes, not $00 bytes.
- I don't know what they're for) followed by a 64 byte entry for each
- file, in the following format:
- OFFSET SIZE USE
- $00 .L file length
- $04 .B unused
- $05 .B file type
- $06 .L dataspace (for exec'able programs)
- $0A .L unused
- $0E .W length of file name
- $10 36 bytes file name
- $34 .L file update date
- $38 .L unused. Supposed to be reference date.
- $3C .L unused. Supposed to be backup date.
-
- The first 64 bytes in the first block of each file contains a copy of
- the directory entry, but most of the information in it is not correct
- (the name is OK, though)
-
- Hope that helps.
-
- - Paul
-
- */
-
-